package edu.thu.studio.ormdesigner.editor.dialog;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.custom.ViewForm;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;

import edu.thu.studio.ormdesigner.Activator;
import edu.thu.studio.ormdesigner.common.AbstractDialog;
import edu.thu.studio.ormdesigner.common.CompositeFactory;
import edu.thu.studio.ormdesigner.model.diagram.link.Link;
import edu.thu.studio.ormdesigner.model.orm.table.Column;
import edu.thu.studio.ormdesigner.model.orm.table.ColumnSet;
import edu.thu.studio.ormdesigner.model.orm.table.RefColumn;
import edu.thu.studio.ormdesigner.model.orm.table.Reference;
import edu.thu.studio.ormdesigner.util.Properties;
import edu.thu.studio.ormdesigner.util.Utils;

public class LinkDialog extends AbstractDialog {

	protected Text codeText;
	protected Text nameText;

	private ViewForm viewForm = null;
	private ToolBar toolBar = null;
	private Composite composite4table = null;
	private Text stereotypeText = null;
	private Table table = null;

	private Hashtable<TableItem, TableItemControls> tablecontrols = new Hashtable<TableItem, TableItemControls>();

	private Composite childComposite;

	private Reference reference;

	private LinkDialog linkDialog = null;

	private List<RefColumn> refColumnList;
	private Map<String, String> keyMapValue = null;

	private String code;
	private String name;
	private String stereotype = null;
	private String referenceId = null;

	// 主键
	private Map<String, String> keyMap = null;
	private List<String> keyArray = null;
	private boolean isCompositekeys = false;

	// 列
	private Map<String, String> columnMap = null;
	private String[] columnArray = null;
	private edu.thu.studio.ormdesigner.model.orm.table.Table ormTable = null;

	public LinkDialog(Shell parentShell, Map<String, String> keyMap,
			edu.thu.studio.ormdesigner.model.orm.table.Table ormTable, Link link) {
		super(parentShell);
		this.keyMap = keyMap;
		this.ormTable = ormTable;
		this.referenceId = link.getReferenceId();

		reference = ormTable.getReferences().getReferenceById(referenceId);

	}

	@Override
	protected void initialize(Composite composite) {
		
		childComposite = CompositeFactory.createChildComposite(composite, 450,
				400, 1, 1);
		
		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 4;
		
		Composite header = new Composite(childComposite, SWT.BORDER_SOLID);
		header.setLayout(gridLayout);
		
		this.codeText = CompositeFactory.createText(null, header,
				Properties.diagram_label_table_general_code, 1,120, false, true);

		this.nameText = CompositeFactory.createText(null, header,
				Properties.diagram_label_table_general_name, 1,120, false, true);

		viewForm = new ViewForm(childComposite, SWT.NONE);

		this.createToolBar();

		viewForm.setTopLeft(toolBar);

		initData();
		createComposite();

		viewForm.setContent(composite4table);

	}

	@Override
	protected void setData() {
		if (null != reference) {
			if (!Utils.isNull(reference.getCode())) {
				this.codeText.setText(reference.getCode());
			}

			if (!Utils.isNull(reference.getName())) {
				this.nameText.setText(reference.getName());
			}

			if (!Utils.isNull(reference.getStereotype())) {
				this.stereotypeText.setText(reference.getStereotype());
			}
		}
	}

	@Override
	protected String getErrorMessage() {
		int count = table.getItemCount();
		if (count <= 0) {
			// return Properties.error_link_noset;
		}
		TableItem[] items = table.getItems();
		for (int i = 0; i < count; i++) {
			TableItem item = items[i];
			String fk = item.getText(1);
			if (Utils.isNull(fk)) {
				return Properties.error_link_somefkisempty;
			}
		}
		for (int i = 0; i < count; i++) {
			TableItem item = items[i];
			String pkfk = keyArray.toString() + item.getText(1);
			for (int j = 1; j < count; j++) {
				TableItem _item = items[j];
				String _pkfk = keyArray.toString() + _item.getText(1);
				if (i != j) {
					if (pkfk.equals(_pkfk)) {
						return Properties.error_link_repeat + ":" + "第"
								+ (j + 1) + "行";
					}
				}
			}
		}
		for (int i = 0; i < count; i++) {
			TableItem item = items[i];
			String fromId = columnMap.get(item.getText(1));
			String toId = keyMap.get(item.getText(0));
			if (Utils.hasReference(fromId, toId, this.ormTable,
					this.referenceId)) {
				return Properties.error_exist_reference;
			}
		}
		return null;
	}

	@Override
	protected void perfomeOK() throws Exception {
		int count = table.getItemCount();
		refColumnList = new ArrayList<RefColumn>();

		this.code = this.codeText.getText().trim();
		this.name = this.nameText.getText().trim();
		this.stereotype = this.stereotypeText.getText().trim();

		if (count > 0) {
			TableItem[] items = table.getItems();
			for (int i = 0; i < count; i++) {
				TableItem item = items[i];
				String toName = item.getText(0);
				String fromName = item.getText(1);
				String to = keyMap.get(toName); // uuid
				String from = columnMap.get(fromName); // uuid
				RefColumn refColumn = new RefColumn();
				refColumn.setId(Utils.getUUID());
				refColumn.setFrom(from);
				refColumn.setTo(to);
				refColumnList.add(refColumn);
			}
		}
	}

	@Override
	protected String getTitle() {
		return Properties.diagram_label_link;
	}

	private void createToolBar() {
		toolBar = new ToolBar(viewForm, SWT.FLAT | SWT.WRAP | SWT.RIGHT);

		final ToolItem remove = new ToolItem(toolBar, SWT.PUSH);
		remove.setText("删除");
		remove.setImage(Activator.getImage(Properties.icon_r_remove));

		// 工具栏按钮事件处理
		Listener listener = new Listener() {
			@Override
			public void handleEvent(Event event) {
				// 如果单击删除按钮
				if (event.widget == remove) {
					// 首先获得表格中所有的行
					TableItem[] items = table.getItems();
					// 循环所有行
					for (int i = items.length - 1; i >= 0; i--) {
						// 如果该行没有被选中，继续循环
						if (!items[i].getChecked())
							continue;
						// 否则选中，查找该表格中是否有该行
						int index = table.indexOf(items[i]);
						// 如果没有该行，继续循环
						if (index < 0)
							continue;
						// 删除绑定的控件
						TableItemControls cons = tablecontrols
								.get(items[index]);
						if (cons != null) {
							cons.dispose();
						}
						// 如果有该行，删除该行
						table.remove(index);
					}

				}
			}

		};
		remove.addListener(SWT.Selection, listener);
	}

	// 创建放置表格的面板
	private void createComposite() {
		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 1;
		composite4table = new Composite(viewForm, SWT.BORDER_SOLID);
		composite4table.setLayout(gridLayout);
		
		createTable();
		createFooter();
	}

	private void createFooter() {
		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 2;

		Composite footer = new Composite(this.composite4table, SWT.NONE);
		footer.setLayout(gridLayout);

		this.stereotypeText = CompositeFactory.createText(null, footer,
				Properties.diagram_label_stereotype, 1, 305, false, true);
	}

	// 创建表格
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void createTable() {
		// 表格布局
		GridData gridData = new GridData();
		gridData.horizontalAlignment = SWT.FILL;
		gridData.grabExcessHorizontalSpace = true;
		gridData.grabExcessVerticalSpace = true;
		gridData.verticalAlignment = SWT.FILL;

		gridData.widthHint = 360;
		gridData.heightHint = 300;

		// 创建表格，使用SWT.FULL_SELECTION样式，可同时选中一行
		table = new Table(composite4table, SWT.MULTI | SWT.FULL_SELECTION
				| SWT.CHECK);
		table.setHeaderVisible(true);// 设置显示表头
		table.setLayoutData(gridData);// 设置表格布局
		table.setLinesVisible(true);// 设置显示表格线/*
		// 创建表头的字符串数组
		String[] tableHeader = {
				isCompositekeys ? Properties.diagram_label_link_keys
						: Properties.diagram_label_link_key,
				Properties.diagram_label_link_column };
		for (int i = 0; i < tableHeader.length; i++) {
			TableColumn tableColumn = new TableColumn(table, SWT.NONE);
			tableColumn.setText(tableHeader[i]);
		}

		// 初始化数据
		TableItem item = null;
		if (null != keyArray) {
			boolean b = false;
			if (null != keyMapValue) {
				Iterator iter = keyMapValue.entrySet().iterator();
				while (iter.hasNext()) {
					Map.Entry<String, String> entry = (Map.Entry<String, String>) iter
							.next();
					String fromId = entry.getKey();
					String toId = entry.getValue();

					if (keyMap.containsValue(toId)) {
						b = true;
						item = new TableItem(table, SWT.NONE);
						item.setText(getKeyValue(fromId, toId));
					}
				}
			}

			if (!b) {
				for (int i = 0; i < keyArray.size(); i++) {
					item = new TableItem(table, SWT.NONE);
					item.setText(new String[] { keyArray.get(i), "" });
				}
			}
		}

		// 添加可编辑的单元格
		TableItem[] items = table.getItems();
		for (int i = 0; i < items.length; i++) {
			// 第一列设置，创建TableEditor对象
			final TableEditor editorKey = new TableEditor(table);
			// 创建一个文本框，用于输入文字
			final Text text = new Text(table, SWT.NONE);
			// 将文本框当前值，设置为表格中的值
			text.setText(items[i].getText(0));
			text.setEnabled(false);
			// 设置编辑单元格水平填充
			editorKey.grabHorizontal = true;
			// 关键方法，将编辑单元格与文本框绑定到表格的第一列
			editorKey.setEditor(text, items[i], 0);

			// 同理，为第二列绑定下 拉框CCombo
			final TableEditor editorColumn = new TableEditor(table);
			final CCombo combo = new CCombo(table, SWT.NONE);
			combo.setItems(columnArray);
			combo.setText(items[i].getText(1));

			// 显示文本
			combo.setText(items[i].getText(1));

			editorColumn.grabHorizontal = true;
			editorColumn.setEditor(combo, items[i], 1);

			combo.addModifyListener(new ModifyListener() {
				public void modifyText(ModifyEvent e) {
					editorColumn.getItem().setText(1, combo.getText());
				}
			});

			// 保存TableItem与绑定Control的对应关系，删除TableItem时使用
			TableItemControls cons = new TableItemControls(text, combo,
					editorKey, editorColumn);
			tablecontrols.put(items[i], cons);
		}
		// 重新布局表格
		for (int i = 0; i < tableHeader.length; i++) {
			table.getColumn(i).pack();
		}

		// 为单元格注册选中事件，校验表单合法性
		table.addListener(SWT.MouseDown, new Listener() {
			public void handleEvent(Event event) {
				if (null != linkDialog) {
					linkDialog.validate();
				}
			}
		});
	}

	private void initData() {
		boolean b = false;
		// 列和uuid
		if (null != ormTable) {
			ColumnSet columnSet = ormTable.getColumns();
			if (null != columnSet) {
				columnMap = new HashMap<String, String>();
				List<Column> columns = columnSet.getObjectList();
				if (null != columns && columns.size() > 0) {
					for (Column column : columns) {
						columnMap.put(column.getName(), column.getId());
						b = true;
					}
				}
			}
		}

		// 列
		if (b) {
			columnArray = new String[columnMap.keySet().size()];
			Iterator<String> iter = columnMap.keySet().iterator();
			int i = 0;
			while (iter.hasNext()) {
				columnArray[i] = iter.next();
				i++;
			}
		}

		// 主键
		if (null != keyMap) {
			keyArray = new ArrayList<String>();
			Iterator<String> iter = keyMap.keySet().iterator();
			while (iter.hasNext()) {
				keyArray.add(iter.next());
			}
			isCompositekeys = keyArray.size() > 1;
		}

		initTableItemData();
	}

	private void initTableItemData() {
		List<Reference> referenceList = ormTable.getReferences()
				.getObjectList();
		if (referenceList.size() > 0) {
			keyMapValue = new HashMap<String, String>();
			for (Reference reference : referenceList) {
				if (null != referenceId
						&& reference.getId().equals(referenceId)) {
					List<RefColumn> refColumnList = reference.getRefColumns()
							.getObjectList();
					for (RefColumn refColumn : refColumnList) {
						keyMapValue.put(refColumn.getFrom(), refColumn.getTo());
					}
				}
			}
		}
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private String[] getKeyValue(String fromId, String toId) {
		String[] str = new String[2];
		Iterator iter = keyMap.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry<String, String> entry = (Map.Entry<String, String>) iter
					.next();
			if (toId.equals(entry.getValue())) {
				str[0] = entry.getKey();
				break;
			}
		}

		iter = columnMap.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry<String, String> entry = (Map.Entry<String, String>) iter
					.next();
			if (fromId.equals(entry.getValue())) {
				str[1] = entry.getKey();
				break;
			}
		}
		return str;
	}

	public void setLinkDialog(LinkDialog linkDialog) {
		this.linkDialog = linkDialog;
	}

	public List<RefColumn> getResult() {
		return this.refColumnList;
	}

	public void setStereotype(String stereotype) {
		this.stereotype = stereotype;
	}

	public String getStereotype() {
		return this.stereotype;
	}

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public class TableItemControls {
		Text text;

		CCombo combo;

		TableEditor tableeditortext;

		TableEditor tableeditorcombo;

		public TableItemControls(Text text, CCombo combo,
				TableEditor tableeditortext, TableEditor tableeditorcombo) {
			this.text = text;
			this.combo = combo;
			this.tableeditortext = tableeditortext;
			this.tableeditorcombo = tableeditorcombo;
		}

		public void dispose() {
			text.dispose();
			combo.dispose();
			tableeditortext.dispose();
			tableeditorcombo.dispose();
		}
	};

}
